/*
 * @Author: hongbin
 * @Date: 2023-03-23 15:19:48
 * @LastEditors: hongbin
 * @LastEditTime: 2023-04-02 21:40:58
 * @Description:
 */
import { FC } from "react";
import * as THREE from "three";
// import { Octree } from "three/examples/jsm/math/Octree.js";
import { Capsule } from "three/examples/jsm/math/Capsule.js";
import Layout from "@/src/components/Three/Layout";
import { ThreeHelper } from "@/src/ThreeHelper";
import { MeshPhysicalMaterial, Object3D } from "three";
import { Octree, getMeshTriangles } from "@/src/ThreeHelper/expand/Octree";

interface IProps {}

const Index: FC<IProps> = () => {
    return <Layout title={"八叉树返回碰撞"} init={init} desc="" />;
};

export default Index;

function init(helper: ThreeHelper) {
    helper.renderer.physicallyCorrectLights = true;
    helper.addAxis();
    helper.addStats();
    helper.frameByFrame();
    helper.addGUI();
    helper.useRoomEnvironment();
    // helper.initLights();

    const worldOctree = new Octree();

    const observer = new THREE.Mesh(
        // new THREE.SphereGeometry(0.3, 32, 32),
        new THREE.BoxGeometry(0.1, 0.5, 0.1),
        new MeshPhysicalMaterial({ color: 0x5511ff, roughness: 0.5 })
    );
    observer.geometry.translate(0, 0.25, 0);
    helper.add(observer);

    const capsule = new Capsule();

    capsule.radius = 0.1;
    capsule.start.set(0, 0.4, 0);
    capsule.end.set(0, 0.1, 0);

    helper.controls.target.copy(helper.camera.position);
    helper.camera.position.copy(helper.controls.target);
    helper.camera.position.z += 2;
    helper.camera.position.y += 1;

    const group = new THREE.Group();

    const floor = helper.generateRect(
        { width: 10, height: 0.1, depth: 10 },
        { color: new THREE.Color("#faa00c") }
    );
    const box = helper.generateRect(
        { width: 1, height: 1, depth: 1 },
        { color: new THREE.Color("#895502") }
    );
    box.position.z -= 1;

    group.add(floor, box);

    const pallet = helper.generateRect(
        {
            width: 1,
            height: 0.1,
            depth: 1,
            widthSegments: 4,
            heightSegments: 4,
            depthSegments: 4,
        },
        { color: new THREE.Color("#021289") }
    );
    pallet.name = "pallet";
    pallet.position.y = 0.1;
    pallet.position.x = 0.4;
    group.add(pallet);
    // helper.add(pallet);

    worldOctree.fromGraphNode(group);

    helper.add(group);

    helper.keyBoardListen();

    const move = new THREE.Vector3();

    const keyEvent = {
        KeyW: (v: Vector3) => {
            v.z -= 0.02;
        },
        KeyS: (v: Vector3) => {
            v.z += 0.02;
        },
        KeyA: (v: Vector3) => {
            v.x -= 0.02;
        },
        KeyD: (v: Vector3) => {
            v.x += 0.02;
        },
        Space: (v: Vector3) => {
            if (onFloor) {
                v.y += 0.8;
            }
        },
    };

    const pressKey = {} as Record<keyof typeof keyEvent, boolean>;
    const keys = Object.keys(keyEvent) as Array<keyof typeof keyEvent>;

    keys.reduce((p, c) => {
        p[c] = false;
        return p;
    }, pressKey);

    for (const key of keys) {
        helper.listenKey(
            key,
            () => {
                pressKey[key] = true;
            },
            () => {
                pressKey[key] = false;
            }
        );
    }

    function moveTranslate(move: Vector3) {
        const vec = move.clone();
        const angle = helper.controls.getAzimuthalAngle();
        vec.applyAxisAngle(THREE.Object3D.DefaultUp, angle);
        return vec;
    }

    const captureMoveVector = new THREE.Vector3();

    let { triangles, translate: palletTranslate } = getMeshTriangles(pallet);
    console.log("triangles:", triangles);
    // const { triangles, translate } = getMeshTriangles(pallet);
    // console.log(triangles);

    let y = 0;
    const consoles = {
        上升: () => {
            y = 0.05;
        },
        下降: () => {
            y = -0.05;
        },
        暂停: () => {
            y = 0;
        },
        isLog: false,
        LOG: () => {
            consoles.isLog = !consoles.isLog;
        },
    };
    helper.gui?.add(consoles, "上升");
    helper.gui?.add(consoles, "下降");
    helper.gui?.add(consoles, "暂停");
    helper.gui?.add(consoles, "LOG");

    let onFloor = false;

    helper.animation(() => {
        const deltaTime = helper.clock.getDelta();

        captureMoveVector.copy(capsule.start);
        const translate = new THREE.Vector3();

        keys.forEach((key) => {
            if (pressKey[key]) {
                keyEvent[key](translate);
            }
        });

        const vec = moveTranslate(translate);
        move.add(vec);

        palletTranslate(new THREE.Vector3(0, y, 0));

        // console.log(onFloor);
        //加入缓冲 使其有一个“作用力”在下坡时得以展现 下坡平滑而不是闪烁 “一上一下”
        let damping = Math.exp(-40 * deltaTime) - 1;

        if (!onFloor) {
            if (y < 0) {
                capsule.translate(new THREE.Vector3(0, y, 0));
            } else {
                move.y -= 0.05;
            }
        }
        move.addScaledVector(move, damping);

        capsule.translate(move);

        const result = worldOctree.capsuleIntersect(
            capsule,
            triangles as THREE.Triangle[]
            // []
        );
        onFloor = false;

        // triangles.forEach((t) => {
        //     console.log(worldOctree.triangleCapsuleIntersect(capsule, t));
        // });
        if (consoles.isLog) {
            console.log(result);
        }

        if (result) {
            onFloor = result.normal.y > 0;
            result.normal.multiplyScalar(result.depth);
            // 使其在地面上时不会下滑 永远 y > 0 小技巧
            result.normal.y -= 0.0000001;
            capsule.translate(result.normal);
        }

        captureMoveVector.sub(capsule.start);

        helper.controls.target.sub(captureMoveVector);
        helper.camera.position.sub(captureMoveVector);
        observer.position.sub(captureMoveVector);

        // move.set(0, 0, 0);
    });
}
